Coverage Report

Created: 2024-12-19 06:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
D:\a\tools.proto\tools.proto\compiler\src\gen\base\structure.rs
Line
Count
Source
1
// Copyright (c) 2024, BlockProject 3D
2
//
3
// All rights reserved.
4
//
5
// Redistribution and use in source and binary forms, with or without modification,
6
// are permitted provided that the following conditions are met:
7
//
8
//     * Redistributions of source code must retain the above copyright notice,
9
//       this list of conditions and the following disclaimer.
10
//     * Redistributions in binary form must reproduce the above copyright notice,
11
//       this list of conditions and the following disclaimer in the documentation
12
//       and/or other materials provided with the distribution.
13
//     * Neither the name of BlockProject 3D nor the names of its contributors
14
//       may be used to endorse or promote products derived from this software
15
//       without specific prior written permission.
16
//
17
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29
use crate::compiler::structure::{Field, FieldRaw, FieldType, FieldView, FixedField, FixedFieldType, Structure};
30
use crate::compiler::util::types::TypeMapper;
31
use crate::gen::base::map::TypePathMapper;
32
use crate::gen::template::hook::{Render, TemplateHooks};
33
use crate::gen::template::{Scope, Template};
34
use crate::model::protocol::{Description, Endianness};
35
use itertools::Itertools;
36
use std::borrow::Cow;
37
38
pub trait Utilities {
39
    fn get_field_type(field_type: FixedFieldType) -> &'static str;
40
    fn get_fragment_name(field: &Field) -> &'static str;
41
    fn get_fragment_name_mut(field: &Field) -> &'static str;
42
    fn get_bit_codec_inline(endianness: Endianness) -> &'static str;
43
    fn get_byte_codec_inline(endianness: Endianness) -> &'static str;
44
    fn get_byte_codec(endianness: Endianness) -> &'static str;
45
0
    fn gen_description(desc: &Description) -> Cow<str> {
46
0
        match desc {
47
0
            Description::Single(v) => Cow::Borrowed(v),
48
0
            Description::Multi(v) => Cow::Owned(v.join(" ")),
49
        }
50
0
    }
51
}
52
53
enum Mode {
54
    Getter,
55
    Setter,
56
}
57
58
impl Mode {
59
792
    pub fn get_path<'a>(&self, getter: &'a str, setter: &'a str) -> &'a str {
60
792
        match self {
61
396
            Mode::Getter => getter,
62
396
            Mode::Setter => setter,
63
        }
64
792
    }
65
}
66
67
702
fn gen_structure_field_prologue<'a, 'fragment, 'variable: 'fragment, U: Utilities>(
68
702
    template: &'variable Template<'fragment, 'variable>,
69
702
    field: &'variable Field,
70
702
) -> Scope<'a, 'fragment, 'variable> {
71
702
    let mut scope = template.scope();
72
702
    scope
73
702
        .var_d("start", field.loc.byte_offset)
74
702
        .var_d("end", field.loc.byte_offset + field.loc.byte_size)
75
702
        .var("name", &field.name)
76
702
        .var(
77
702
            "description",
78
702
            field.description.as_ref().map(U::gen_description).unwrap_or("".into()),
79
702
        )
80
702
        .var_d("info", field);
81
702
    scope
82
702
}
83
84
468
fn gen_structure_field<U: Utilities, G: FnMut(Mode, &Field, &FixedField, Scope) -> String>(
85
468
    mode: Mode,
86
468
    field: &Field,
87
468
    template: &Template,
88
468
    field_generator: &mut G,
89
468
) -> Option<String> {
90
468
    let mut scope = gen_structure_field_prologue::<U>(template, field);
91
468
    match &field.ty {
92
396
        FieldType::Fixed(v) => {
93
396
            let bits_type = U::get_field_type(v.bits_type);
94
396
            let raw_type = U::get_field_type(v.raw_type);
95
396
            scope
96
396
                .var("bits_type", bits_type)
97
396
                .var("raw_type", raw_type)
98
396
                .var_d("bit_offset", field.loc.bit_offset)
99
396
                .var_d("bit_size", field.loc.bit_size);
100
396
            Some(field_generator(mode, field, v, scope))
101
        }
102
72
        _ => None,
103
    }
104
468
}
105
106
118
fn gen_structure<'variable, U: Utilities, G: FnMut(Mode, &Field, &FixedField, Scope) -> String>(
107
118
    s: &'variable Structure,
108
118
    mut template: Template<'_, 'variable>,
109
118
    mut field_generator: G,
110
118
) -> String {
111
118
    template.var("struct_name", &s.name).var(
112
118
        "struct_description",
113
118
        s.description.as_ref().map(U::gen_description).unwrap_or("".into()),
114
118
    );
115
118
    let getters = s
116
118
        .fields
117
118
        .iter()
118
234
        .filter_map(|v| gen_structure_field::<U, G>(Mode::Getter, v, &template, &mut field_generator))
119
118
        .join("");
120
118
    let setters = s
121
118
        .fields
122
118
        .iter()
123
234
        .filter_map(|v| gen_structure_field::<U, G>(Mode::Setter, v, &template, &mut field_generator))
124
118
        .join("");
125
118
    let mut code = template.render("", &["decl"]).unwrap();
126
118
    if !getters.is_empty() {
  Branch (126:8): [True: 53, False: 6]
  Branch (126:8): [True: 53, False: 6]
  Branch (126:8): [True: 0, False: 0]
  Branch (126:8): [True: 0, False: 0]
  Branch (126:8): [Folded - Ignored]
127
106
        code += &template.var("fields", getters).render("", &["getters"]).unwrap();
128
106
    
}12
129
118
    if !setters.is_empty() {
  Branch (129:8): [True: 53, False: 6]
  Branch (129:8): [True: 53, False: 6]
  Branch (129:8): [True: 0, False: 0]
  Branch (129:8): [True: 0, False: 0]
  Branch (129:8): [Folded - Ignored]
130
106
        code += &template.var("fields", setters).render("", &["setters"]).unwrap();
131
106
    
}12
132
118
    code
133
118
}
134
135
198
fn gen_field_raw<'variable>(
136
198
    mode: Mode,
137
198
    _: &'variable Field,
138
198
    fixed: &'variable FixedField,
139
198
    mut scope: Scope<'_, '_, 'variable>,
140
198
) -> String {
141
198
    let path = mode.get_path("getters.field", "setters.field");
142
198
    match &fixed.raw {
143
        FieldRaw::Transmute => {
144
72
            if fixed.raw_type == FixedFieldType::Bool {
  Branch (144:16): [True: 24, False: 48]
  Branch (144:16): [Folded - Ignored]
145
24
                scope.render_to_var(path, &["transmute_bool"], "fragment").unwrap()
146
            } else {
147
48
                scope.render_to_var(path, &["transmute_other"], "fragment").unwrap()
148
            }
149
        }
150
20
        FieldRaw::SignedCast(max_positive) => {
151
20
            scope.var_d("max_positive", max_positive).render_to_var(path, &["signed"], "fragment").unwrap()
152
        }
153
106
        FieldRaw::None => scope.render_to_var(path, &["none"], "fragment").unwrap(),
154
    };
155
198
    scope.render(mode.get_path("getters", "setters"), &["field"]).unwrap()
156
198
}
157
158
198
fn gen_field_bin<'variable, U: Utilities>(
159
198
    mode: Mode,
160
198
    field: &'variable Field,
161
198
    fixed: &'variable FixedField,
162
198
    mut scope: Scope<'_, '_, 'variable>,
163
198
) -> String {
164
198
    let fragment_name = U::get_fragment_name(field);
165
198
    if field.loc.bit_size % 8 != 0 {
  Branch (165:8): [True: 64, False: 134]
  Branch (165:8): [True: 0, False: 0]
  Branch (165:8): [Folded - Ignored]
166
64
        let path = mode.get_path("getters.field.bit", "setters.field.bit");
167
64
        scope
168
64
            .var("codec", U::get_bit_codec_inline(fixed.endianness))
169
64
            .render_to_var(path, &[fragment_name], "fragment")
170
64
            .unwrap();
171
134
    } else {
172
134
        let path = mode.get_path("getters.field.byte", "setters.field.byte");
173
134
        scope
174
134
            .var("codec", U::get_byte_codec_inline(fixed.endianness))
175
134
            .render_to_var(path, &[fragment_name], "fragment")
176
134
            .unwrap();
177
134
    }
178
198
    scope.render(mode.get_path("getters", "setters"), &["field"]).unwrap()
179
198
}
180
181
117
fn gen_field_getter<U: Utilities, T: TypeMapper>(
182
117
    field: &Field,
183
117
    template: &Template,
184
117
    type_path_map: &TypePathMapper<T>,
185
117
) -> String {
186
117
    let mut scope = gen_structure_field_prologue::<U>(template, field);
187
117
    match &field.ty {
188
99
        FieldType::Fixed(v) => gen_field_view_getter::<U, T>(v, &scope, type_path_map),
189
6
        FieldType::Array(v) => scope
190
6
            .var("raw_type", U::get_field_type(v.ty))
191
6
            .var("codec", U::get_byte_codec(v.endianness))
192
6
            .var_d("bit_size", v.item_bit_size)
193
6
            .render("getters", &["array"])
194
6
            .unwrap(),
195
12
        FieldType::Struct(v) => scope.var("type_name", type_path_map.get(v)).render("getters", &["struct"]).unwrap(),
196
    }
197
117
}
198
199
117
fn gen_field_setter<U: Utilities, T: TypeMapper>(
200
117
    field: &Field,
201
117
    template: &Template,
202
117
    type_path_map: &TypePathMapper<T>,
203
117
) -> String {
204
117
    let mut scope = gen_structure_field_prologue::<U>(template, field);
205
117
    match &field.ty {
206
99
        FieldType::Fixed(v) => gen_field_view_setter::<U, T>(v, &scope, type_path_map),
207
6
        FieldType::Array(v) => scope
208
6
            .var("raw_type", U::get_field_type(v.ty))
209
6
            .var("codec", U::get_byte_codec(v.endianness))
210
6
            .var_d("bit_size", v.item_bit_size)
211
6
            .render("setters", &["array"])
212
6
            .unwrap(),
213
12
        FieldType::Struct(v) => scope.var("type_name", type_path_map.get(v)).render("setters", &["struct"]).unwrap(),
214
    }
215
117
}
216
217
99
fn gen_field_view_getter<U: Utilities, T: TypeMapper>(
218
99
    field: &FixedField,
219
99
    scope: &Scope,
220
99
    type_path_map: &TypePathMapper<T>,
221
99
) -> String {
222
99
    let mut scope = scope.clone();
223
99
    scope.var("raw_type", U::get_field_type(field.raw_type));
224
99
    match &field.view {
225
4
        FieldView::Float { a, b, .. } => scope
226
4
            .var("view_type", U::get_field_type(field.view_type))
227
4
            .var("a", format!("{:?}", a))
228
4
            .var("b", format!("{:?}", b))
229
4
            .render("getters", &["view_float"])
230
4
            .unwrap(),
231
6
        FieldView::Enum(r) => scope
232
6
            .var("view_type", type_path_map.get(r))
233
6
            .var("repr_type", U::get_field_type(r.repr_type))
234
6
            .render("getters", &["view_enum"])
235
6
            .unwrap(),
236
89
        FieldView::None => scope
237
89
            .var("view_type", U::get_field_type(field.view_type))
238
89
            .render("getters", &["view_none"])
239
89
            .unwrap(),
240
    }
241
99
}
242
243
99
fn gen_field_view_setter<U: Utilities, T: TypeMapper>(
244
99
    field: &FixedField,
245
99
    scope: &Scope,
246
99
    type_path_map: &TypePathMapper<T>,
247
99
) -> String {
248
99
    let mut scope = scope.clone();
249
99
    scope.var("raw_type", U::get_field_type(field.raw_type));
250
99
    match &field.view {
251
4
        FieldView::Float { a_inv, b_inv, .. } => scope
252
4
            .var("view_type", U::get_field_type(field.view_type))
253
4
            .var("a_inv", format!("{:?}", a_inv))
254
4
            .var("b_inv", format!("{:?}", b_inv))
255
4
            .render("setters", &["view_float"])
256
4
            .unwrap(),
257
6
        FieldView::Enum(r) => scope
258
6
            .var("view_type", type_path_map.get(r))
259
6
            .var("repr_type", U::get_field_type(r.repr_type))
260
6
            .render("setters", &["view_enum"])
261
6
            .unwrap(),
262
89
        FieldView::None => scope
263
89
            .var("view_type", U::get_field_type(field.view_type))
264
89
            .render("setters", &["view_none"])
265
89
            .unwrap(),
266
    }
267
99
}
268
269
59
fn gen_structure_getters<U: Utilities, T: TypeMapper>(
270
59
    s: &Structure,
271
59
    template: &Template,
272
59
    type_path_map: &TypePathMapper<T>,
273
59
) -> String {
274
59
    let mut scope = template.scope();
275
117
    let fields = s.fields.iter().map(|v| gen_field_getter::<U, T>(v, template, type_path_map)).join("");
276
59
    scope.var("fields", fields).render("", &["getters"]).unwrap()
277
59
}
278
279
59
fn gen_structure_setters<U: Utilities, T: TypeMapper>(
280
59
    s: &Structure,
281
59
    template: &Template,
282
59
    type_path_map: &TypePathMapper<T>,
283
59
) -> String {
284
59
    let mut scope = template.scope();
285
117
    let fields = s.fields.iter().map(|v| gen_field_setter::<U, T>(v, template, type_path_map)).join("");
286
59
    scope.var("fields", fields).render("", &["setters"]).unwrap()
287
59
}
288
289
pub struct Templates<'fragment, 'variable> {
290
    pub field_template: Template<'fragment, 'variable>,
291
    pub template: Template<'fragment, 'variable>,
292
    pub bits_template: Template<'fragment, 'variable>,
293
    pub raw_template: Template<'fragment, 'variable>,
294
}
295
296
59
pub fn generate<'variable, U: Utilities, T: TypeMapper>(
297
59
    templates: Templates<'_, 'variable>,
298
59
    s: &'variable Structure,
299
59
    type_path_map: &TypePathMapper<T>,
300
59
    hooks: &TemplateHooks,
301
59
) -> String {
302
59
    let mut template = templates.template;
303
59
    let mut field_template = templates.field_template;
304
59
    field_template.var("struct_name", &s.name).var(
305
59
        "struct_description",
306
59
        s.description.as_ref().map(U::gen_description).unwrap_or("".into()),
307
59
    );
308
59
    template.var("name", &s.name).var_d("byte_size", s.byte_size).var(
309
59
        "struct_description",
310
59
        s.description.as_ref().map(U::gen_description).unwrap_or("".into()),
311
59
    );
312
59
    let mut code = template.render("", &["decl", "new", "fixed_size", "write_to", "from_bytes"]).unwrap();
313
59
    for 
frag22
in hooks.get_fragments("ext") {
314
22
        code += &template.render_frag(frag).unwrap();
315
22
    }
316
59
    code += &gen_structure_getters::<U, T>(s, &field_template, type_path_map);
317
59
    code += &gen_structure_setters::<U, T>(s, &field_template, type_path_map);
318
198
    code += &gen_structure::<U, _>(s, templates.bits_template, |mode, field, fixed, scope| {
319
198
        gen_field_bin::<U>(mode, field, fixed, scope)
320
198
    });
321
198
    code += &gen_structure::<U, _>(s, templates.raw_template, |mode, field, fixed, scope| {
322
198
        gen_field_raw(mode, field, fixed, scope)
323
198
    });
324
59
    code
325
59
}